﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace NZBMatrixAdvancedFeedReader.Classes
{
    public class MovieFeed
    {

        #region Events

        public delegate void dlgProgressChanged(int percentage);
        /// <summary>
        /// This event helps to trace the progress of search.
        /// </summary>
        public static dlgProgressChanged ProcessChanged;

        #endregion

        #region Properties

        public string Title { get; set; }
        public string Guid { get; set; }
        public string Link { get; set; }
        public string Description { get; set; }
        public string Category { get; set; }
        public string CategoryId { get; set; }
        public string CatText { get; set; }
        public string EnclosureUrl { get; set; }
        public string EnclosureLength { get; set; }
        public string EnclosureType { get; set; }

        public string MovieName { get; set; }
        public string MovieCategory { get; set; }
        public string FileSize { get; set; }
        public string MovieAdded { get; set; }
        public string MovieYear { get; set; }
        public string MovieGroup { get; set; }
        public string IMDBLink { get; set; }
        public string MovieGenre { get; set; }
        public string MovieRate { get; set; }
        public Color MovieRateColor { get; set; }
        public string MovieRateVotes { get; set; }
        public string MovieImageUrl { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Parses the XML from Feed loads and create MovieFeed obejct.
        /// It also connects to IMDB to get Release Year and Movie Rate.
        /// </summary>
        /// <param name="feedXML"></param>
        /// <returns></returns>
        public static List<MovieFeed> FromXML(string feedXML)
        {

            XDocument xd;
            List<MovieFeed> feedList;

            xd = XDocument.Parse(feedXML);
            feedList = new List<MovieFeed>();

            InvokeProcessChanged(0);

            int MaxCount;

            MaxCount = xd.Element("rss").Element("channel").Elements("item").Count();

            for (int i = 0; i < MaxCount; i++)
            {
                InvokeProcessChanged(i * 100 / MaxCount);
                XElement e = xd.Element("rss").Element("channel").Elements("item").ElementAt(i);
                feedList.Add(MovieFeed.FromItemElement(e));
            }

            return feedList;

        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Read the XML and assign the properties to the MovieFeed Object.
        /// Then it will search the IMDB to fetch actual movie information.
        /// </summary>
        /// <param name="newFeed"></param>
        /// <param name="itemElement"></param>
        private static void InitializeProperties(ref MovieFeed newFeed, XElement itemElement)
        {

            newFeed.Title = itemElement.Element("title").Value;
            newFeed.Guid = itemElement.Element("guid").Value;
            newFeed.Link = itemElement.Element("link").Value;
            newFeed.Description = itemElement.Element("description").Value;
            newFeed.Category = itemElement.Element("category").Value;
            newFeed.CatText = itemElement.Element("cattext").Value;
            newFeed.CategoryId = itemElement.Element("categoryid").Value;
            newFeed.EnclosureUrl = itemElement.Element("enclosure").Attribute("url").Value;
            newFeed.EnclosureLength = itemElement.Element("enclosure").Attribute("length").Value;
            newFeed.EnclosureType = itemElement.Element("enclosure").Attribute("type").Value;

            newFeed.FileSize = ParseDescriptionToMovieSize(newFeed.Description).Trim();
            newFeed.IMDBLink = ParseDescriptionToIMDBLink(newFeed.Description);

            //  Reads the movie information from the IMDB .
            GetInfoFromIMDB(ref newFeed);

        }

        /// <summary>
        /// Retrieves Movie Information from IMDB.
        /// </summary>
        /// <param name="newFeed"></param>
        private static void GetInfoFromIMDB(ref MovieFeed newFeed)
        {

            //  Get  IMDB Info
            if (newFeed.IMDBLink != "N/A")
            {
                //  Use mobile link for faster connection
                string IMDBMobileLink = newFeed.IMDBLink.Replace("www.", "m.");
                //Fix exception in IMDB Link
                IMDBMobileLink = IMDBMobileLink.Replace("http://IMDb :", "");

                string html = CommonTasks.ReadURLToString(IMDBMobileLink, 32000);

                if (html.Length > 0)
                {
                    newFeed.MovieName = ParseIMDBToGetTitle(html);
                    if (!string.IsNullOrEmpty(newFeed.MovieName) && newFeed.MovieName != "N/A")
                    {
                        newFeed.MovieName = newFeed.MovieName.Replace(" - IMDb", "");
                        newFeed.MovieYear = newFeed.MovieName.Substring(newFeed.MovieName.Length - 6, 4);
                        newFeed.MovieName = newFeed.MovieName.Substring(0, newFeed.MovieName.Length - 7).Trim();
                        newFeed.MovieName = CommonTasks.FixHexStrings(newFeed.MovieName);
                    }

                    newFeed.MovieRate = ParseIMDBToGetRate(html);
                    if (!string.IsNullOrEmpty(newFeed.MovieRate) && newFeed.MovieRate != "N/A")
                    {
                        newFeed.MovieRateVotes = newFeed.MovieRate.Substring(newFeed.MovieRate.IndexOf(@"&#40;")+5);
                        newFeed.MovieRate = newFeed.MovieRate.Split('<')[0];

                        // Get Movie Rate Color
                        float f;
                        if (float.TryParse(newFeed.MovieRate, out f))
                        {
                            if (f <= 4)
                                newFeed.MovieRateColor = Color.Red;
                            else if (f > 4 && f < 7)
                                newFeed.MovieRateColor = Color.LightYellow;
                            else if (f >= 7)
                                newFeed.MovieRateColor = Color.Green;
                        }
                        else
                            newFeed.MovieRateColor = SystemColors.Control;

                    }

                    newFeed.MovieImageUrl = ParseIMDBToGetImageLink(html);
                    if (!string.IsNullOrEmpty(newFeed.MovieImageUrl) && newFeed.MovieImageUrl != "N/A")
                    {
                    }


                }

            }

        }

        /// <summary>
        /// Find the Movie Tumbnail from IMDB.
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string ParseIMDBToGetImageLink(string html)
        {
            int index1;
            int index2;

            index1 = html.IndexOf(@"meta property='og:image' content='");

            if (index1 >= 0)
            {
                index1 = html.IndexOf("http://", index1);
                if (index1 >= 0)
                {
                    index2 = html.IndexOf(@"'", index1);
                    if (index2 > 0)
                    {
                        return html.Substring(index1, index2 - index1);
                    }
                }
            }

            return "N/A";
        }

        /// <summary>
        /// Get the Movie Rate from the IMDB.
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string ParseIMDBToGetRate(string html)
        {
            int index1;
            int index2;

            index1 = html.IndexOf(@"<p class=""votes"">");
            if (index1 >= 0)
            {
                index1 += 30;
                index2 = html.IndexOf("votes", index1);
                if (index2 > 0)
                {
                    return html.Substring(index1, index2 - index1 );
                }
            }

            return "N/A";
        }

        /// <summary>
        /// Get the movie title from IMDB.
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string ParseIMDBToGetTitle(string html)
        {
            int index1;
            int index2;

            index1 = html.IndexOf("<title>");
            if (index1 >= 0)
            {
                index1 += 7;
                index2 = html.IndexOf("<", index1);
                if (index2 > 0)
                {
                    return html.Substring(index1, index2 - index1);
                }
            }

            return "N/A";
        }

        /// <summary>
        /// Parse NZBMatrix feed's Descriotion field to get IMDB link.
        /// </summary>
        /// <param name="descriptionHTML"></param>
        /// <returns></returns>
        private static string ParseDescriptionToIMDBLink(string descriptionHTML)
        {
            int index1;
            int index2;

            index1 = descriptionHTML.IndexOf("<b>IMDB Link:</b>");
            if (index1 >= 0)
            {
                index1 = descriptionHTML.IndexOf("href=", index1);
                if (index1 >= 0)
                {
                    index1 += 6;
                    index2 = descriptionHTML.IndexOf(">", index1);
                    if (index2 > 0)
                    {
                        return descriptionHTML.Substring(index1, index2 - index1 - 1);
                    }
                }
            }

            // Use NFO section to get to IMDB link 

            index1 = descriptionHTML.IndexOf("<BR /><b>NFO:</b>");
            if (index1 >= 0)
            {
                index1 = descriptionHTML.IndexOf("href=", index1);
                if (index1 >= 0)
                {
                    index1 += 6;
                    index2 = descriptionHTML.IndexOf(">", index1);
                    if (index2 > 0)
                    {
                        // I couldn't login to NZBMatrix to get IMDB link inside the page. Feel free to shared your suggestions.
                        return descriptionHTML.Substring(index1, index2 - index1 - 1);
                    }
                }
            }

            return "N/A";
        }

        /// <summary>
        /// Parse NZBMatrix feed's Descriotion field to get movie file size.
        /// </summary>
        /// <param name="descriptionHTML"></param>
        /// <returns></returns>
        private static string ParseDescriptionToMovieSize(string descriptionHTML)
        {

            int index1;
            int index2;

            index1 = descriptionHTML.IndexOf("<b>Size:</b>");
            if (index1 >= 0)
            {
                index1 += 12;
                index2 = descriptionHTML.IndexOf("<br", index1);
                if (index2 > 0)
                {
                    return descriptionHTML.Substring(index1, index2 - index1);
                }
            }

            return "N/A";

        }

        /// <summary>
        /// Create MovieFeed from XElement.
        /// </summary>
        /// <param name="itemElement"></param>
        /// <returns></returns>
        private static MovieFeed FromItemElement(XElement itemElement)
        {
            MovieFeed newFeed;

            newFeed = new MovieFeed();

            InitializeProperties(ref newFeed, itemElement);

            return newFeed;

        }

        private static void InvokeProcessChanged(int percentage)
        {
            if (ProcessChanged != null)
                ProcessChanged(percentage);
        }

        #endregion

    }

}